package net.yeah.mickey_zhouyou.database.file_manage;

import java.io.File;
import java.util.Date;

import net.yeah.mickey_zhouyou.database.cache.EntityCache;
import net.yeah.mickey_zhouyou.database.cache.RelationshipCache;
import net.yeah.mickey_zhouyou.database.cache.SequenceCache;
import net.yeah.mickey_zhouyou.database.domain.BaseEntity;
import net.yeah.mickey_zhouyou.database.domain.BaseRelationship;
import net.yeah.mickey_zhouyou.database.exception.SaveXMLFailException;
import net.yeah.mickey_zhouyou.database.sequence.Sequence;
import net.yeah.mickey_zhouyou.database.util.ClassFieldsCache;
import net.yeah.mickey_zhouyou.database.util.ConfigProperties;
import net.yeah.mickey_zhouyou.database.util.XMLUtil;

import org.w3c.dom.Document;

/**
 * 文件管理类。
 * 
 * @author Mickey
 * 
 */
public abstract class FileManager {

	static {
		initDBDir();
	}

	private static final String SUFFIX = ".xml";

	private static <E extends BaseEntity> String getEntityDir(E e) {
		return ConfigProperties.getEntityRootPath() + e.getClass().getName()
				+ "/";
	}

	private static <E extends BaseEntity> String getEntityPath(E e) {
		return getEntityDir(e) + +e.getId() + "_" + e.getVersionTm().getTime()
				+ SUFFIX;
	}

	private static <T extends BaseRelationship<?, ?>> String getRelationshipDir(
			T r) {
		return ConfigProperties.getRelationshipRootPath()
				+ r.getClass().getName() + "/";
	}

	private static <T extends BaseRelationship<?, ?>> String getRelationshipPath(
			T r) {
		return getRelationshipDir(r) + r.getLeftId() + "_" + r.getRightId()
				+ "_" + r.getVersionTm().getTime() + SUFFIX;
	}

	private static String getSequenceDir() {
		return ConfigProperties.getSequenceRootPath();
	}

	private static String getSequencePath(Sequence seq) {
		return getSequenceDir() + seq.getEntityName() + SUFFIX;
	}

	/**
	 * 保存entity类型的对象。 如果配置为不保存历史记录，那么删除老数据。
	 * 
	 * @param <E>
	 * @param e
	 */
	public static <E extends BaseEntity> void save(E e) {
		if (!ConfigProperties.isSaveHistoryVersion()) {
			delete(e);
		}
		ClassFieldsCache.setValue(e, "versionTm", new Date());

		String dir = getEntityDir(e);
		initDbDir(dir);

		File file = new File(getEntityPath(e));
		save(XMLUtil.toDoc(e), file);
	}

	/**
	 * 保存关系类型的对象。如果配置为不保存历史记录，那么删除老数据。
	 * 
	 * @param <T>
	 * @param r
	 */
	public static <T extends BaseRelationship<?, ?>> void save(T r) {
		if (!ConfigProperties.isSaveHistoryVersion()) {
			delete(r);
		}
		ClassFieldsCache.setValue(r, "versionTm", new Date());

		String dir = getRelationshipDir(r);
		initDbDir(dir);

		File file = new File(getRelationshipPath(r));
		save(XMLUtil.toDoc(r), file);
	}

	/**
	 * 保存Sequence对象，Sequence对象不保存历史记录。
	 * 
	 * @param seq
	 */
	public static void save(Sequence seq) {
		File file = new File(getSequencePath(seq));
		save(XMLUtil.toDoc(seq), file);
	}

	/**
	 * 删除实体对象。如果保存历史记录，那么只把isValid属性设为false。如果不保存历史记录，那么直接删掉。
	 * 
	 * @param <E>
	 * @param e
	 */
	public static <E extends BaseEntity> void delete(E e) {
		if (ConfigProperties.isSaveHistoryVersion()) {
			ClassFieldsCache.setValue(e, "isValid", false);
			save(e);
		} else {
			File file = new File(getEntityPath(e));
			if (file.exists())
				file.delete();
		}
	}

	/**
	 * 删除关系对象。如果保存历史记录，那么只把isValid属性设为false。如果不保存历史记录，那么直接删掉。
	 * 
	 * @param <R>
	 * @param r
	 */
	public static <R extends BaseRelationship<?, ?>> void delete(R r) {
		if (ConfigProperties.isSaveHistoryVersion()) {
			ClassFieldsCache.setValue(r, "isValid", false);
			save(r);
		} else {
			File file = new File(getRelationshipPath(r));
			if (file.exists())
				file.delete();
		}
	}

	private static void save(Document doc, File file) {
		try {
			XMLUtil.saveDocument(doc, file);
		} catch (Exception exception) {
			exception.printStackTrace();
			throw new SaveXMLFailException(exception);
		}
	}

	/**
	 * 读取所有的数据到缓存中。
	 */
	public static void loadDataToCache() {
		loadEntityToCache();
		loadRelationshipToCache();
		loadSequenceToCache();
	}

	/**
	 * 初始化实体根目录，关系根目录和Sequence根目录。
	 */
	private static void initDBDir() {
		initDbDir(ConfigProperties.getEntityRootPath());
		initDbDir(ConfigProperties.getRelationshipRootPath());
		initDbDir(ConfigProperties.getSequenceRootPath());
	}

	private static void initDbDir(String dir) {
		File entityDir = new File(dir);
		if (!entityDir.exists())
			entityDir.mkdirs();
		if (entityDir.isFile()) {
			entityDir.delete();
			entityDir.mkdirs();
		}
	}

	private static void loadEntityToCache() {
		File file = new File(ConfigProperties.getEntityRootPath());
		File[] fs = file.listFiles();
		for (File f : fs) {
			File[] fs2 = f.listFiles();
			for (File f2 : fs2) {
				try {
					EntityCache
							.addEntity(XMLUtil.toEntity(XMLUtil.loadDoc(f2)));
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	private static void loadRelationshipToCache() {
		File file = new File(ConfigProperties.getRelationshipRootPath());
		File[] fs = file.listFiles();
		for (File f : fs) {
			File[] fs2 = f.listFiles();
			for (File f2 : fs2) {
				try {
					RelationshipCache.addRelationship(XMLUtil
							.toRelationship(XMLUtil.loadDoc(f2)));
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	private static void loadSequenceToCache() {
		File file = new File(ConfigProperties.getSequenceRootPath());
		File[] fs = file.listFiles();
		for (File f : fs) {
			try {
				SequenceCache
						.addSequence(XMLUtil.toSequence(XMLUtil.loadDoc(f)));
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

}
